package logic;

import java.util.Random;

/**
 * class representing player (computer or human)
 * @author Rekin
 *
 */
public class Player {
	
	private Card cards[];
	private String name;
	private int money;
	private boolean inGame;
	private boolean bankrupt;
	private boolean moved;
	private int givenStake;
	//fields for sequence counting
	private int sequenceKind;
	private int sequenceHighest;
	private int sequence2ndPair;
	private int highestCard;
	private int sequenceHighestColor;
	private int highestCardColor;
	private String seqTxt;
	private boolean[] selectedCards;
	
	/**
	 * onstructor for player
	 * @param startingMoney starting player money
	 */
	public Player(int startingMoney){
		sequenceKind=-1;
		sequenceHighest=-1;
		sequenceHighestColor=-1;
		highestCard=-1;
		highestCardColor=-1;
		sequence2ndPair=-1;
		cards=new Card[5];
		selectedCards=new boolean[]{false,false,false,false,false};
		money=startingMoney;
		inGame=true;
		bankrupt=false;
		moved=false;
		seqTxt="";
		givenStake=0;
	}
	
	/**
	 * resets player's variables for a new round
	 */
	public void resetPlayerForNewRound(){
		sequenceKind=-1;
		sequenceHighest=-1;
		sequenceHighestColor=-1;
		highestCard=-1;
		highestCardColor=-1;
		sequence2ndPair=-1;
		selectedCards=new boolean[]{false,false,false,false,false};
		inGame=true;
		moved=false;
		seqTxt="";
		givenStake=0;
	}
	
	/**
	 * initiates player's cards from a given card deck
	 * @param cardDeck
	 */
	public void initCards(int[][] cardDeck){
		int fig,col;
		Random r = new Random();
	    
		for(int i=0;i<5;++i){
			do{
				fig=Math.abs(r.nextInt())%13+2;
				col=Math.abs(r.nextInt())%4;
				}
				while(cardDeck[col][fig-2]==0);  
					//recursive non-repeatable randomization ;)
			
			cardDeck[col][fig-2]=0;
			cards[i]=new Card(fig,col);
		}
	}
	
	/**
	 * method for determining if player should give double stake
	 * @return true if player should give double stake otherwise false
	 */
	public boolean doDoubleStake(){
		if(sequenceKind>1){
			return true;
		}
		return false;
	}
	
	/**
	 * @param fig figure to be parsed to String
	 * @return String representing figure
	 */
	private String cardFigureToString(int fig){
		if(fig<=10) return ""+fig;
		else if(fig==11) return "J";
		else if(fig==12) return "Q";
		else if(fig==13) return "K";
		else if(fig==14) return "A";
		return null;
	}
	
	/**
	 * @param col color to be parsed to String
	 * @return String representing color
	 */
	private String cardColorToString(int col){
		if(col==0) return "-KI";
		else if(col==1) return "-KA";
		else if(col==2) return "-PI";
		else if(col==3) return "-TR";

		return null;
	}
	
	/**
	 * method for sorting cards
	 */
	public void cardSort() {
		for (int i = 0; i < cards.length - 1; ++i) {
			for (int j = i + 1; j < cards.length; ++j) {
				if (cards[i].compareToAnotherCard(cards[j]) > 0) {
					//Exchange elements
					Card temp = cards[i];
					cards[i] = cards[j];
					cards[j] = temp;
				}
			}
		}
	}
	
	/**
	 * method for exchanging cards
	 * @param cardDeck card deck with available cards
	 */
	public void exchangeCards(int[][] cardDeck){
		int fig,col;
		Random r = new Random();
		for(int i=0;i<5;++i){
			if(!cards[i].isSelected()) continue;
			do{
				fig=Math.abs(r.nextInt())%13+2;
				col=Math.abs(r.nextInt())%4;
				}
				while(cardDeck[col][fig-2]==0);
			cardDeck[col][fig-2]=0;
			cards[i]=new Card(fig,col);
		}
	}
	
	/**
	 * sets cards as selected or not
	 * @param a card 0 selection
	 * @param b card 1 selection
	 * @param c card 2 selection
	 * @param d card 3 selection
	 * @param e card 4 selection
	 */
	public void setSelectedCards(boolean a,boolean b,boolean c,boolean d,boolean e){
		selectedCards[0]=a;
		selectedCards[1]=b;
		selectedCards[2]=c;
		selectedCards[3]=d;
		selectedCards[4]=e;
	}
	
	/**
	 * sets card with given index as selected
	 * @param i card index
	 */
	private void setSelectedCard(int i){
		selectedCards[i]=true;
	}
	
	/**
	 * counts computer players sequences
	 */
	public void preCountCards(){ //check computer player sequence
		if(poker()){
		}
		else if(fourOfKind()){
		}
		else if(full()){
		}
		else if(color()){
		}
		else if(straight()){
		}
		else if(threeOfKind()){
		}
		else if(twoPairs()){
		}
		else if(pair()){
		}
		else{
			highCard();
		}
	}
	
	/**
	 * counts cards sequences
	 */
	public void countCards(){
		if(poker()){
			seqTxt="!!!!Poker!!!!";
		}
		else if(fourOfKind()){
			seqTxt="4 of a kind: "+cardFigureToString(sequenceHighest);
		}
		else if(full()){
			seqTxt="Full house: 3x-"+cardFigureToString(sequenceHighest)+
			" , 2x-"+cardFigureToString(sequence2ndPair);
		}
		else if(color()){
			seqTxt="Color: of"+cardColorToString(sequenceHighestColor)+
						", from "+cardFigureToString(sequenceHighest);
		}
		else if(straight()){
			seqTxt="Straight: to "+cardFigureToString(sequenceHighest);
		}
		else if(threeOfKind()){
			seqTxt="3 of a kind: "+cardFigureToString(sequenceHighest);
		}
		else if(twoPairs()){
			seqTxt="2 pairs: "+cardFigureToString(sequenceHighest)+" , "+
			cardFigureToString(sequence2ndPair);
		}
		else if(pair()){
			seqTxt="1 pair: "+cardFigureToString(sequenceHighest);
		}
		else{
			highCard();
			seqTxt=("High card: "+cardFigureToString(sequenceHighest)+
					cardColorToString(sequenceHighestColor));
		}
	}
	
	/**
	 * @param index card index
	 * @return Card object with given object
	 */
	public Card getCard(int index){
		return cards[index];
	}
	
	
	////////////////////////////logic for sequence finder///////////////////////
	
	/**
	 * logic for finding highCard
	 */
	private boolean highCard(){
		if(!color() && !pair() && !straight()){
			sequenceHighest=cards[4].getFigure();
			sequenceHighestColor=cards[4].getColor();
			highestCard=cards[3].getFigure();
			highestCardColor=cards[3].getColor();
			sequenceKind=0;
			setSelectedCards(false,false,false,false,true);
			return true;
		}
		return false;
	}
	
	/**
	 * logic for finding pair
	 */
	private boolean pair(){
		int prevCard=cards[0].getFigure();
		for(int i=1;i<5;++i){
			if(prevCard==cards[i].getFigure()){
				sequenceHighest=cards[i].getFigure();
				sequenceHighestColor=cards[i].getColor();
				setSelectedCard(i);
				setSelectedCard(i-1);
				highestCard=cards[4].getFigure();
				highestCardColor=cards[4].getColor();
				if(i==4){
					highestCard=cards[2].getFigure();
					highestCardColor=cards[2].getColor();
				}
				sequenceKind=1;
				return true;
			}
			else{
				prevCard=cards[i].getFigure();
			}
		}
		return false;
	}
	
	/**
	 * logic for finding two pairs
	 */
	private boolean twoPairs(){
		if(cards[0].getFigure()==cards[1].getFigure() && cards[2].getFigure()==cards[3].getFigure()){
			highestCard=cards[4].getFigure();
			highestCardColor=cards[4].getColor();
			sequenceHighest=cards[3].getFigure();
			sequenceHighestColor=cards[3].getColor();
			sequence2ndPair=cards[0].getFigure();
			setSelectedCard(0);
			setSelectedCard(1);
			setSelectedCard(2);
			setSelectedCard(3);
			sequenceKind=2;
			return true;
		}
		else if(cards[0].getFigure()==cards[1].getFigure() && cards[3].getFigure()==cards[4].getFigure()){
			highestCard=cards[2].getFigure();
			highestCardColor=cards[2].getColor();
			sequenceHighest=cards[4].getFigure();
			sequenceHighestColor=cards[4].getColor();
			sequence2ndPair=cards[0].getFigure();
			setSelectedCard(0);
			setSelectedCard(1);
			setSelectedCard(3);
			setSelectedCard(4);
			sequenceKind=2;
			return true;
		}
		else if(cards[1].getFigure()==cards[2].getFigure() && cards[3].getFigure()==cards[4].getFigure()){
			highestCard=cards[0].getFigure();
			highestCardColor=cards[0].getColor();
			sequenceHighest=cards[4].getFigure();
			sequenceHighestColor=cards[4].getColor();
			sequence2ndPair=cards[1].getFigure();
			setSelectedCard(1);
			setSelectedCard(2);
			setSelectedCard(3);
			setSelectedCard(4);
			sequenceKind=2;
			return true;
		}
		return false;
	}
	
	/**
	 * logic for finding three of a kind
	 */
	private boolean threeOfKind(){
		int sameCards=0;
		int prevCard=cards[0].getFigure();
		for(int i=1;i<5;++i){
			if(cards[i].getFigure()==prevCard){ 
				++sameCards;
				if(sameCards==2){
					highestCard=cards[4].getFigure();
					highestCardColor=cards[4].getColor();
					if(i==4){
						highestCard=cards[1].getFigure();
						highestCardColor=cards[1].getColor();
					}
					sequenceHighest=cards[i].getFigure();
					sequenceHighestColor=cards[i].getColor();
					setSelectedCard(i);
					setSelectedCard(i-1);
					setSelectedCard(i-2);
					sequenceKind=3;
					return true;
				}
			}
			else{
				if(i==1 || i==2){
					prevCard=cards[i].getFigure();
					sameCards=0;
				}
				else{
					return false;
				}
			}
			
		}

		return false;
	}
	
	/**
	 * logic for finding four of a kind
	 */
	private boolean fourOfKind(){
		int sameCards=0;
		int prevCard=cards[0].getFigure();
		for(int i=1;i<5;++i){
			if(cards[i].getFigure()==prevCard){
				++sameCards;
				if(sameCards==3){
					highestCard=cards[4].getFigure();
					highestCardColor=cards[4].getColor();
					if(i==4){
						highestCard=cards[0].getFigure();
						highestCardColor=cards[0].getColor();
					}
					sequenceHighest=cards[i].getFigure();
					sequenceHighestColor=cards[i].getColor();
					setSelectedCard(i);
					setSelectedCard(i-1);
					setSelectedCard(i-2);
					setSelectedCard(i-3);
					sequenceKind=7;
					return true;
				}
			}
			else{
				if(i==1){
					prevCard=cards[i].getFigure();
					sameCards=0;
				}
				else{
					return false;
				}
			}
		}
		return false;
	}
	
	/**
	 * logic for finding full house
	 */
	private boolean full(){
		if( cards[0].getFigure()==cards[1].getFigure() && cards[1].getFigure()==cards[2].getFigure()
				&& cards[3].getFigure()==cards[4].getFigure() ) {
			sequenceHighest=cards[2].getFigure();
			sequenceHighestColor=cards[2].getColor();
			sequence2ndPair=cards[4].getFigure();
			setSelectedCards(true,true,true,true,true);
			sequenceKind=6;
			return true;
		}
		if( cards[0].getFigure()==cards[1].getFigure() && 
				cards[2].getFigure()==cards[3].getFigure()
					&& cards[3].getFigure()==cards[4].getFigure() ){
			sequenceHighest=cards[4].getFigure();
			sequenceHighestColor=cards[4].getColor();
			sequence2ndPair=cards[0].getFigure();
			sequenceKind=6;
			return true;
		}
		return false;
	}
	
	/**
	 * logic for finding straight
	 */
	private boolean straight(){
		int prevCard=cards[0].getFigure();
		for(int i=1;i<5;++i){
			if(cards[i].getFigure()-1==prevCard){
				++prevCard;
			}
			else
				return false;
		}
		sequenceHighest=cards[4].getFigure();
		sequenceHighestColor=cards[4].getColor();
		setSelectedCards(true,true,true,true,true);
		sequenceKind=4;
		return true;
	}
	
	/**
	 * logic for finding color
	 */
	private boolean color(){
		int col=cards[0].getColor();
		for(int i=1;i<5;++i){
			if(cards[i].getColor()!=col) 
				return false;
		}
		sequenceHighest=cards[4].getFigure();
		sequenceHighestColor=cards[4].getColor();
		setSelectedCards(true,true,true,true,true);
		sequenceKind=5;
		return true;
	}
	
	/**
	 * logic for finding poker
	 */
	private boolean poker(){
		if(!color())
			return false;
		int prevCard=cards[0].getFigure();
		for(int i=1;i<5;++i){
			if(cards[i].getFigure()-1==prevCard){
				++prevCard;
			}
			else
				return false;
		}
		sequenceHighest=cards[4].getFigure();
		sequenceHighestColor=cards[4].getColor();
		setSelectedCards(true,true,true,true,true);
		sequenceKind=8;
		return true;
	}
	
	/**
	 * checks if player is bankrupt and if so sets his status
	 */
	public void checkBankrupcy(){
		if(money<0){
			bankrupt=true;
		}
	}

	/**
	 * @param name
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return player name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @return player money
	 */
	public int getMoney() {
		return money;
	}

	/**
	 * @param money
	 */
	public void setMoney(int money) {
		this.money = money;
	}

	/**
	 * @return selected cards
	 */
	public boolean[] getSelectedCards() {
		return selectedCards;
	}

	/**
	 * @return if player is in game
	 */
	public boolean isInGame() {
		return inGame;
	}

	/**
	 * @param inGame
	 */
	public void setInGame(boolean inGame) {
		this.inGame = inGame;
		if(inGame==false){
			seqTxt="Dropped";
		}
	}

	/**
	 * @return bankrupt state
	 */
	public boolean isBankrupt() {
		return bankrupt;
	}

	/**
	 * @param bankrupt
	 */
	public void setBankrupt(boolean bankrupt) {
		this.bankrupt = bankrupt;
	}

	/**
	 * @return sequence text representation
	 */
	public String getSeqTxt() {
		return seqTxt;
	}

	/**
	 * sets sequence text representation
	 * @param seqTxt sequence text representation
	 */
	public void setSeqTxt(String seqTxt) {
		this.seqTxt = seqTxt;
	}

	/**
	 * @return if player has moved
	 */
	public boolean isMoved() {
		return moved;
	}

	/**
	 * @param moved
	 */
	public void setMoved(boolean moved) {
		this.moved = moved;
	}
	
	/**
	 * @return sequenceKind
	 */
	public int getSequenceKind() {
		return sequenceKind;
	}
	
	/**
	 * @return sequenceHighest card
	 */
	public int getSequenceHighest() {
		return sequenceHighest;
	}
	
	/**
	 * @return highestCardColor
	 */
	public int getHighestCardColor() {
		return highestCardColor;
	}
	
	/**
	 * @param amount money to be added to player's account
	 */
	public void addMoney(int amount){
		money+=amount;
	}
	
	/**
	 * @param amount money to be substracted from player's account
	 */
	public void substractMoney(int amount){
		money-=amount;
	}
	
	/**
	 * @return player's givenStake
	 */
	public int getGivenStake() {
		return givenStake;
	}
	
	/**
	 * @param givenStake
	 */
	public void setGivenStake(int givenStake) {
		this.givenStake = givenStake;
	}
	
	/**
	 * @return highestCard
	 */
	public int getHighestCard() {
		return highestCard;
	}
	
	/**
	 * sets a card to a given one
	 * @param cardIndex index of card to be set
	 * @param color card color
	 * @param figure card figure
	 */
	public void setCard(int cardIndex, int color, int figure){
		cards[cardIndex].setColor(color);
		cards[cardIndex].setFigure(figure);
	}
}
